import { ReactiveEffect } from './effect'

class ComputedRefImpl {
    private _getters;

    /**
     * 是否重新计算（代表是否重新获取数据）
     */
    private _dirty = true;
    /**
     * 缓存数据
     */
    private _value;

    private _effect;
    constructor(getters) {
        // 通过传入的 getter ，作为一个依赖进行收集， 此时并不调用 effet.run 方法
        // 同时利用 effect 的第二个参数 scheduler ，触发 _dirty 重新计算标识 更新为 true 
        // 注意：这里的 scheduler 触发由依赖触发节点触发，依赖节点触发由 reative 对象的 proxy set 触发。
        // 所以在 test 中，reative(value).foo 响应式对象 foo = 2 重新赋值时，能够触发 scheduler . 
        // 而依赖收集动作依赖于 第一次访问 get value 时，由 this._effect.run() 触发。
        this._effect = new ReactiveEffect(getters, () => {
            if (!this._dirty) {
                // 更新重新计算标识
                this._dirty = true;
            }
        });
        this._getters = getters;
    }

    get value() {
        if (this._dirty) {
            // 标记重新计算标识为 false 
            this._dirty = false;
            // 缓存一个值，标记不修改为 true，这个 value 就一直返回缓存
            // 注意： 这里很巧妙的使用来对 _value 进行赋值，同时 _effect.run 会触发 activeEffect（最后一个调用过的 effect ）， shouldTrack （需要依赖收集标签 = true） 这两个的初始化
            // 这里其实是进行了依赖收集，核心是 activeEffect 的激活，最终会导致成功收集依赖。
            this._value = this._effect.run();
        }

        return this._value;
    }
}

export function computed(getter) {
    const comptedRef = new ComputedRefImpl(getter);
    return comptedRef;
}